#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
汽车制造公司涂装-总装缓存区调序调度优化问题 - Problem 1 (Enhanced)
增强版PBS优化调度模型实现
"""

import pandas as pd
import numpy as np
import itertools
from collections import defaultdict
import warnings
warnings.filterwarnings('ignore')

class EnhancedPBSOptimizer:
    def __init__(self):
        self.data = None
        self.car_info = {}
        self.color_map = {'燃动': 'combustion', '电动': 'electric'}
        self.drive_map = {'两驱': 'two', '四驱': 'four'}
        
    def load_data(self):
        """加载输入数据"""
        # 读取附件1数据
        self.data = pd.read_excel('附件1.xlsx')
        self.data.columns = ['sequence', 'config', 'color', 'drive']
        
        # 基于实际数据创建映射
        color_mapping = {'燃动': 'combustion', '电动': 'electric', 'ȼ��': 'combustion', '�춯': 'electric'}
        drive_mapping = {'两驱': 'two', '四驱': 'four', '����': 'two', '����': 'four'}
        
        # 创建车辆信息字典
        for _, row in self.data.iterrows():
            self.car_info[row['sequence']] = {
                'config': row['config'],
                'color': color_mapping.get(row['color'], row['color']),
                'drive': drive_mapping.get(row['drive'], row['drive']),
                'original_color': row['color'],
                'original_drive': row['drive']
            }
        
        print(f"加载数据完成，共{len(self.data)}条记录")
        print(f"颜色分布: {dict(self.data['color'].value_counts())}")
        print(f"驱动分布: {dict(self.data['drive'].value_counts())}")
        return self.data
    
    def calculate_color_switching_score(self, sequence):
        """计算颜色切换得分 (目标1)"""
        color_sequence = [self.car_info[car]['original_color'] for car in sequence]
        
        switches = 0
        for i in range(1, len(color_sequence)):
            if color_sequence[i] != color_sequence[i-1]:
                switches += 1
        
        # 基于切换次数计算得分，最多切换次数为len-1
        max_switches = len(sequence) - 1
        if max_switches > 0:
            score = max(0, 100 - (switches / max_switches) * 100)
        else:
            score = 100
            
        return score, switches
    
    def calculate_drive_ratio_score(self, sequence):
        """计算驱动形式比例得分 (目标2)"""
        drive_sequence = [self.car_info[car]['original_drive'] for car in sequence]
        
        total_deviation = 0
        window_size = 4
        
        for i in range(0, len(drive_sequence), window_size):
            window = drive_sequence[i:i+window_size]
            if len(window) < 2:
                continue
                
            two_count = window.count('两驱')
            four_count = window.count('四驱')
            
            # 计算与1:1比例的偏差
            ideal_two = len(window) / 2.0
            ideal_four = len(window) / 2.0
            
            deviation = abs(two_count - ideal_two) + abs(four_count - ideal_four)
            total_deviation += deviation
        
        # 计算得分
        max_possible_deviation = len(drive_sequence)  # 最坏情况
        if max_possible_deviation > 0:
            score = max(0, 100 - (total_deviation / max_possible_deviation) * 100)
        else:
            score = 100
            
        return score, total_deviation
    
    def calculate_pbs_utilization_score(self, schedule):
        """计算PBS缓存区利用率得分 (目标3)"""
        used_positions = np.sum(schedule > 0)
        total_positions = schedule.shape[0] * schedule.shape[1]
        utilization = used_positions / total_positions
        
        # 返回利用率得分，利用率越高越好
        score = utilization * 100
        return score, utilization
    
    def calculate_time_score(self, schedule):
        """计算总调度时间得分 (目标4)"""
        # 计算实际调度时间
        max_col_time = 0
        for col in range(schedule.shape[1]):
            col_cars = schedule[:, col]
            col_cars = col_cars[col_cars > 0]
            if len(col_cars) > 0:
                # 每列调度时间 = 车辆数 * 9 + 设置时间
                col_time = len(col_cars) * 9 + 12
                max_col_time = max(max_col_time, col_time)
        
        # 计算理论最小时间
        total_cars = np.sum(schedule > 0)
        min_time = 9 * total_cars + 72  # 基于题目公式
        
        # 计算时间偏差
        time_deviation = max(0, max_col_time - min_time)
        time_penalty = time_deviation * 0.1
        
        score = max(0, 100 - time_penalty)
        return score, max_col_time, min_time
    
    def create_initial_sequence(self):
        """创建初始车辆序列"""
        return list(range(1, len(self.data) + 1))
    
    def optimize_by_color_grouping(self, sequence):
        """基于颜色分组优化"""
        # 按颜色分组
        color_groups = defaultdict(list)
        for car_id in sequence:
            color = self.car_info[car_id]['original_color']
            color_groups[color].append(car_id)
        
        # 按颜色顺序排列
        optimized_sequence = []
        for color in sorted(color_groups.keys()):
            optimized_sequence.extend(color_groups[color])
        
        return optimized_sequence
    
    def optimize_by_drive_balancing(self, sequence):
        """基于驱动形式平衡优化"""
        # 将序列分成4车一组
        groups = []
        for i in range(0, len(sequence), 4):
            group = sequence[i:i+4]
            groups.append(group)
        
        # 在每个组内平衡驱动形式
        optimized_groups = []
        for group in groups:
            # 分离两驱和四驱
            two_drive = [car for car in group if self.car_info[car]['original_drive'] == '两驱']
            four_drive = [car for car in group if self.car_info[car]['original_drive'] == '四驱']
            
            # 交错排列以达到平衡
            optimized_group = []
            two_ptr, four_ptr = 0, 0
            
            while two_ptr < len(two_drive) or four_ptr < len(four_drive):
                if two_ptr < len(two_drive):
                    optimized_group.append(two_drive[two_ptr])
                    two_ptr += 1
                if four_ptr < len(four_drive):
                    optimized_group.append(four_drive[four_ptr])
                    four_ptr += 1
            
            # 填充剩余位置
            while len(optimized_group) < len(group):
                if two_ptr < len(two_drive):
                    optimized_group.append(two_drive[two_ptr])
                    two_ptr += 1
                elif four_ptr < len(four_drive):
                    optimized_group.append(four_drive[four_ptr])
                    four_ptr += 1
            
            optimized_groups.append(optimized_group)
        
        # 合并所有组
        optimized_sequence = []
        for group in optimized_groups:
            optimized_sequence.extend(group)
        
        return optimized_sequence[:len(sequence)]
    
    def create_schedule_matrix(self, sequence):
        """创建10xN的调度矩阵"""
        n_cars = len(sequence)
        n_cols = max(100, (n_cars + 9) // 10)  # 确保足够的列数
        
        schedule = np.zeros((10, n_cols), dtype=int)
        
        car_index = 0
        for col in range(n_cols):
            for row in range(10):
                if car_index < n_cars:
                    schedule[row, col] = sequence[car_index]
                    car_index += 1
                else:
                    break
            if car_index >= n_cars:
                break
        
        return schedule
    
    def calculate_all_scores(self, sequence, schedule):
        """计算所有目标得分"""
        obj1_score, color_switches = self.calculate_color_switching_score(sequence)
        obj2_score, drive_deviation = self.calculate_drive_ratio_score(sequence)
        obj3_score, utilization = self.calculate_pbs_utilization_score(schedule)
        obj4_score, actual_time, min_time = self.calculate_time_score(schedule)
        
        # 计算加权总分
        weights = {'obj1': 0.4, 'obj2': 0.3, 'obj3': 0.2, 'obj4': 0.1}
        total_score = (obj1_score * weights['obj1'] + 
                      obj2_score * weights['obj2'] + 
                      obj3_score * weights['obj3'] + 
                      obj4_score * weights['obj4'])
        
        return {
            'color_switching': {'score': obj1_score, 'value': color_switches},
            'drive_ratio': {'score': obj2_score, 'value': drive_deviation},
            'pbs_utilization': {'score': obj3_score, 'value': utilization},
            'total_time': {'score': obj4_score, 'value': actual_time},
            'total_score': total_score
        }
    
    def solve_problem1(self):
        """求解问题1"""
        print("=== 开始求解Problem 1 ===")
        
        # 加载数据
        self.load_data()
        
        # 初始序列
        initial_sequence = self.create_initial_sequence()
        initial_schedule = self.create_schedule_matrix(initial_sequence)
        
        # 计算初始得分
        initial_scores = self.calculate_all_scores(initial_sequence, initial_schedule)
        
        # 颜色优化
        color_optimized = self.optimize_by_color_grouping(initial_sequence)
        color_schedule = self.create_schedule_matrix(color_optimized)
        color_scores = self.calculate_all_scores(color_optimized, color_schedule)
        
        # 驱动形式优化
        drive_optimized = self.optimize_by_drive_balancing(initial_sequence)
        drive_schedule = self.create_schedule_matrix(drive_optimized)
        drive_scores = self.calculate_all_scores(drive_optimized, drive_schedule)
        
        # 组合优化
        combined_optimized = self.optimize_by_drive_balancing(
            self.optimize_by_color_grouping(initial_sequence))
        combined_schedule = self.create_schedule_matrix(combined_optimized)
        combined_scores = self.calculate_all_scores(combined_optimized, combined_schedule)
        
        # 选择最佳方案
        strategies = {
            'initial': (initial_sequence, initial_schedule, initial_scores),
            'color_optimized': (color_optimized, color_schedule, color_scores),
            'drive_optimized': (drive_optimized, drive_schedule, drive_scores),
            'combined_optimized': (combined_optimized, combined_schedule, combined_scores)
        }
        
        best_strategy = max(strategies.items(), key=lambda x: x[1][2]['total_score'])
        best_sequence, best_schedule, best_scores = best_strategy[1]
        
        # 输出结果
        print("\n=== 优化结果 ===")
        print(f"最佳策略: {best_strategy[0]}")
        print(f"总得分: {best_scores['total_score']:.2f}")
        print("\n各项得分:")
        for key in ['color_switching', 'drive_ratio', 'pbs_utilization', 'total_time']:
            print(f"  {key}: {best_scores[key]['score']:.2f} (值: {best_scores[key]['value']:.2f})")
        
        # 生成结果文件
        self.generate_results(best_sequence, best_schedule, best_scores)
        
        return best_sequence, best_schedule, best_scores
    
    def generate_results(self, sequence, schedule, scores):
        """生成结果文件"""
        
        # 1. 生成调度矩阵 (result11.xlsx)
        schedule_df = pd.DataFrame(schedule)
        schedule_df.to_excel('result11.xlsx', index=False, header=False)
        
        # 2. 生成车辆序列 (result12.xlsx)
        sequence_data = []
        for car_id in sequence:
            if car_id > 0:  # 只添加有效车辆
                car_data = self.car_info[car_id]
                sequence_data.append({
                    '车辆顺序': car_id,
                    '车型': car_data['config'],
                    '动力': car_data['original_color'],
                    '驱动': car_data['original_drive']
                })
        
        sequence_df = pd.DataFrame(sequence_data)
        sequence_df.to_excel('result12.xlsx', index=False)
        
        # 3. 生成详细得分报告
        score_report = pd.DataFrame([{
            '优化目标': '颜色切换',
            '得分': scores['color_switching']['score'],
            '实际值': scores['color_switching']['value'],
            '权重': 0.4
        }, {
            '优化目标': '驱动比例',
            '得分': scores['drive_ratio']['score'],
            '实际值': scores['drive_ratio']['value'],
            '权重': 0.3
        }, {
            '优化目标': '缓存区利用率',
            '得分': scores['pbs_utilization']['score'],
            '实际值': scores['pbs_utilization']['value'],
            '权重': 0.2
        }, {
            '优化目标': '总调度时间',
            '得分': scores['total_time']['score'],
            '实际值': scores['total_time']['value'],
            '权重': 0.1
        }, {
            '优化目标': '加权总分',
            '得分': scores['total_score'],
            '实际值': scores['total_score'],
            '权重': 1.0
        }])
        
        score_report.to_excel('problem1_scores.xlsx', index=False)
        
        print("\n=== 结果文件生成完成 ===")
        print("result11.xlsx - 调度矩阵")
        print("result12.xlsx - 车辆序列")
        print("problem1_scores.xlsx - 详细得分报告")

def main():
    """主函数"""
    optimizer = EnhancedPBSOptimizer()
    sequence, schedule, scores = optimizer.solve_problem1()
    
    return sequence, schedule, scores

if __name__ == "__main__":
    main()